﻿#include "person.h"
#include "drive.h"

enum
{
    PROP_0,
    PROP_AGE,
    PROP_PHONE,
    PROP_MAX,
};

static GParamSpec *props[PROP_MAX]={NULL,};

static void person_constructed(GObject *obj);
static void person_finalize(GObject *obj);
static void person_set_property (GObject         *object,
                         guint            prop_id,
                         const GValue    *value,
                         GParamSpec      *pspec);
static void person_get_property (GObject         *object,
                         guint            prop_id,
                         GValue          *value,
                         GParamSpec      *pspec);

#if PERSON_WITH_DRIVE_IFACE
static void person_drive_iface_init(DriveInterface *iface);

G_DEFINE_TYPE_WITH_CODE(Person, person, G_TYPE_OBJECT,
                            G_ADD_PRIVATE(Person)
                            G_IMPLEMENT_INTERFACE(DRIVE_TYPE, person_drive_iface_init))
#else
G_DEFINE_TYPE_WITH_PRIVATE(Person, person, G_TYPE_OBJECT)
#endif

//we should implement person_class_init() and person_init() required by the above macro, G_DEFINE_TYPE_WITH_PRIVATE()
static void person_class_init(PersonClass *klass)
{
    g_message("person_class_init ...\n");
    g_print("person_class_init ...\n");
    GObjectClass *objClass = G_OBJECT_CLASS(klass);

    //连接callback funcptr
    objClass->constructed = person_constructed;
    objClass->finalize = person_finalize;
    objClass->get_property = person_get_property;
    objClass->set_property = person_set_property;

    //注册props
    props[PROP_AGE] = g_param_spec_int("age"
        , "the age"
        , NULL
        , 0, 150
        , 0
        , G_PARAM_READWRITE | G_PARAM_STATIC_NICK | G_PARAM_EXPLICIT_NOTIFY);
    props[PROP_PHONE] = g_param_spec_string("phone"
        , "the phone number"
        , NULL
        , "000-000-00000"
        , G_PARAM_READWRITE | G_PARAM_STATIC_NICK | G_PARAM_EXPLICIT_NOTIFY);

    g_object_class_install_properties(objClass, PROP_MAX, props);
}

static void person_set_property (GObject         *object,
                         guint            prop_id,
                         const GValue    *value,
                         GParamSpec      *pspec)
{
    Person *person = PERSON(object);
    //PersonPrivate *priv = person->priv;

    switch(prop_id)
    {
    case PROP_AGE:
        person_set_age(person, g_value_get_int(value));
        break;
    case PROP_PHONE:
        person_set_phone(person, g_value_get_string(value));
        break;
    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
        break;
    }
}


static void person_get_property (GObject         *object,
                         guint            prop_id,
                         GValue          *value,
                         GParamSpec      *pspec)
{
    Person *person = PERSON(object);
    //PersonPrivate *priv = person->priv;

    switch(prop_id)
    {
    case PROP_AGE:
        g_value_set_int(value, person_get_age(person));
        break;
    case PROP_PHONE:
        g_value_set_string(value, person_get_phone(person));
        break;
    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
        break;
    }
}

static void person_init(Person *obj)
{
    g_print("person_init ...\n");
    PersonPrivate *priv;

    //设置Person.priv
    priv = person_get_instance_private(obj);
    obj->priv = priv;

    //alloc value and set init value.
    priv->m_name = g_string_new(NULL);  
    priv->m_age = 0;
    priv->m_phone = NULL;

}

static void person_constructed(GObject *obj)
{
    g_print("person_constructed ...\n");

    //Person *person = PERSON (obj);
    //PersonPrivate *priv = person->priv;

    G_OBJECT_CLASS (person_parent_class)->constructed (obj);    //父类方法
}

static void person_finalize(GObject *obj)
{
    g_print("person_finalize ...\n");

    Person *person = PERSON (obj);
    PersonPrivate *priv = person->priv;

    //destroy memory
    g_string_free(priv->m_name, TRUE);    
    priv->m_name = NULL;
    g_clear_pointer(&priv->m_phone, g_free);
    
    G_OBJECT_CLASS (person_parent_class)->finalize(obj);    //父类方法
}



Person* person_new(void)
{
    g_print("person_new ...\n");

    return g_object_new(PERSON_TYPE, NULL);
}

void person_set_name(Person* obj, const gchar *name)
{
    g_print("person_set_name ...\n");

    g_return_if_fail(IS_PERSON(obj));
    g_string_assign(obj->priv->m_name, name);    
}

GString* person_get_name(Person* obj)
{
    g_print("person_get_name ...\n");
    g_return_val_if_fail(IS_PERSON(obj), NULL);
    return obj->priv->m_name;
}

void person_set_age(Person* obj, int age)
{
    g_print("person_set_age ...\n");

    g_return_if_fail(IS_PERSON(obj));
    obj->priv->m_age = age;
    g_object_notify_by_pspec(G_OBJECT(obj), props[PROP_AGE]);
}

int person_get_age(Person* obj)
{
    g_print("person_get_age ...\n");
    g_return_val_if_fail(IS_PERSON(obj), 0);
    return obj->priv->m_age;
}

void person_set_phone(Person* obj, const gchar *phone)
{
    g_print("person_set_phone ...\n");

    g_return_if_fail(IS_PERSON(obj));
    g_free(obj->priv->m_phone);
    obj->priv->m_phone = g_strdup(phone);

    g_object_notify_by_pspec(G_OBJECT(obj), props[PROP_PHONE]);
}

const gchar* person_get_phone(Person* obj)
{
    g_print("person_get_phone ...\n");
    g_return_val_if_fail(IS_PERSON(obj), NULL);
    return obj->priv->m_phone;
}


gboolean person_is_a_driver(Person* obj)
{
    g_print("person_is_a_driver ...\n");
    g_return_val_if_fail(IS_PERSON(obj), FALSE);
    return FALSE;
}


#if PERSON_WITH_DRIVE_IFACE

static void person_doDrive(Drive *inst)
{
    g_print("person_doDrive....\n");
}

static void person_drive_iface_init(DriveInterface *iface)
{
    iface->doDrive = person_doDrive;
}

#endif
